package com.cctc.juc.source.Bitc.Glock.dlock;
/**
 * 【分布式锁】
 * 简介：依据锁的应用场景，可以划分为本地锁和分布式锁。
 * - 本地锁：JVM 进程内的数据同步锁，解决单体系统多线程之间互斥访问共享资源的问题，包括 Java 内置锁和 JUC 显式锁。
 * - 分布式锁：跨 JVM 进程间的数据同步锁，解决分布式系统之间互斥访问共享资源的问题，可以使用 MySQL 数据库、Zookeeper | Etcd 等分布式协调工具、Redis 分布式缓存等进行实现，其中，在高并发环境下，使用 Redis 实现分布式锁的方式是使用最多的。
 * 2. 分布式锁的基本要求：独占、公平、可重入、非阻塞抢锁、限时阻塞抢锁、可中断抢锁、手动释放锁、自动过期释放锁，以及分布式系统的高可用、高性能等基本要求。
 * 3. 分布式锁实现方案
 * 在目前分布式锁的实现方案中，比较成熟、主流的方案有两种：
 * 1）分布式数据库锁，依靠 MySQL 等底层数据库提供的（悲观、乐观）锁机制来真正保证数据访问的排他性。
 * a. 悲观锁 [开启事务 -> select...for update 加锁 -> 数据更新操作 -> 提交事务]
 * -----
 * begin;                   # 1. 开启事务
 * select ... for update    # 2. 加锁
 * ...  ...                 # 3. 数据操作
 * commit;                  # 4. 提交事务
 * -----
 * b. 乐观锁 [无锁，CAS 操作（先比较版本号再执行数据更新操作），MVCC 多版本并发控制（解决 ABA 问题）]
 * --> 特点：完全依靠数据库的可用性，但性能不高。
 * 2）分布式协调锁，基于 Zookeeper、Etcd 等分布式数据管理与协调工具实现的分布式锁；
 * a. Zookeeper（Poxis 协议开源实现代表 [zab 原子广播协议]，闭源实现代表为 Google 的 Chubby 组件）
 * --> 原理：借鉴 AQS 思想，基于 Zookeeper 的临时顺序节点及（前驱）节点监听机制实现的分布式锁，例如 Curator 客户端提供的 InterProcessMutex 可重入锁。
 * --> 特点：完全高可用，但性能不是太高。
 * b. Etcd（Raft 协议的开源实现代表）
 * ... ...
 * 3）分布式缓存锁，基于 Redis 实现的分布式锁。
 * --> 原理：基于 setnx(set if not exists) 和 expire 命令的原子组合（lua 脚本）实现的分布式锁。
 * 提示：大部分开源框架（例如 Redission 中的分布式锁组件，都是使用 lua 脚本实现的），因为在 eval 命令执行 lua 代码时，会被当成一个命令去执行，直到执行完毕，redis 才会执行其他命令，以达到原子操作的目的。
 * a. 定义 lua 加锁逻辑（加锁命令 [setnx, 独占锁], 锁名称 [lockKey], 加锁对象标识 [requestId], 过期时间 [ttl]）脚本。
 * b. 定义 lua 解锁逻辑（加锁对象标识 [requestId], 解锁命令 [del], 锁名称 [lockKey]）脚本。
 * c. 使用 jedis.eval() 方法分别执行 lua 脚本，完成加锁和解锁功能。
 * 小心：STW 、网络抖动、客户端宕机等导致的锁过期问题。
 * - 问题描述：client1 在持锁期间发生了 fullGC，且其 STW 停顿时间超过了锁的过期时间，被 redis 自动释放了，此时 client2 占有了锁，然而 client1 在代码层面仍（假）持有锁，client1 & client2 同时执行临界区代码块，破坏了互斥约束，从而引发线程安全问题。
 * - 解决方案：
 * a. 借鉴 CAS 乐观锁思想，（入侵代码）数据层面增加（token、version）版本号；
 * b.（Redission）使用 watch dog 看门狗（后台线程，非入侵）监控锁 & 自动续期机制。
 * --> 特点：高性能，可用性可以通过其他方案去弥补。
 * [Redis 分布式锁的高可用问题] client1 --加锁--> master 实例 --主从同步--> slave1、slave2... 实例 --master 实例宕机--> slave2 被切换成 master 实例（但还没有同步到前 master 实例的加锁记录）--> client2 --加锁，导致多个客户端同时持有同一个分布式锁，破坏了互斥约束，引发数据安全问题。
 * 解决方案：Redis 联（合）锁（MultiLock）、红（过半）锁（RedLock）。
 * 算法思想：为了保证分布式锁的高可用，应该在整个 redis 集群上创建联（合）锁（MultiLock）或者红（过半）锁（RedLock），保证必须在全部或大多数 redis 节点上都成功创建后，才能算整个 redis 集群加锁成功，避免仅仅在一个 redis 实例上加锁而带来的数据安全问题。
 * 提示：在 CAP 理论中，偏向于追求 AP 而不是 CP，而高可用的 Redis 联（合）锁（MultiLock）、红（过半）锁（RedLock）会导致性能降低，不建议在生产环境中使用；如果为了追求 CP，建议使用 Zookeeper 分布式锁。
 * 因此，在高并发环境下，极致追求于 AP，使用 Redis + Lua 实现分布式锁的方式是使用最多的（熟练、精通）。
 */